
# 设置默认flash位置
# HC32F448 flash操作
# 必须以4对齐


#   AC      0x40022000
#   KEY     0x40022004
#   OPTKEY  0x40022008
#   STS     0x4002200C
#   CTRL    0x40022010
#   ADD     0x40022014
#   OB      0x4002201C
#   WRP     0x40022020
#   ECC     0x40022024
#   RDN     0x4002202C
#   CAHR    0x40022030


#HC32F448
    #页大小     8KBytes 0x2000

#解锁保护寄存器
# UNLOCK_FAPRT_KEY1 0x0123
# UNLOCK_FAPRT_KEY2 0x3210
# # 一些操作数据
set flash_addr {
    EFM_FAPRT   0x40010400
    EFM_FSTP    0x40010404
    EFM_FRMC    0x40010408
    EFM_FWMC    0x4001040c
    EFM_FSR     0x40010410

    EFM_FSCLR   0x40010414
    EFM_FITE    0x40010418
    EFM_FSWP    0x4001041c

    EFM_FPMTSW  0x40010420
    EFM_FPMTEW  0x40010424

    FEM_UQID1   0x40010450
    EFM_UQID2   0x40010454
    EFM_UQID3   0x40010458

    EFM_WLOCK   0x40010580
    EFM_F0NWPRT 0x40010590

    UNLOCK_FAPRT_KEY1 0x0123
    UNLOCK_FAPRT_KEY2 0x3210


    UNLOCK_KEY1 0x01234567
    UNLOCK_KEY2 0xfedcba98

    COLERR  0x20
    OPTEND  0x10
    PEWERR  0x1
    PEPRTERR 0x2
    PGSZERR 0x4
    PGMISMTCH 0x8

    PAGE_SIZE       0x2000
    FLASH_END       0x00040000
    FLASH_ADDR      0x00000000
}


    # 一些flash的信息, 1个page大小2kB

# global flash_addr

# echo $::flash_addr(KEY)
# echo $::flash_addr(UNLOCK_KEY1)
# echo 22222222222222222

# proc xxxx { } {
#     echo $::flash_addr(KEY)
#     echo $::flash_addr(UNLOCK_KEY1)
#     echo 333333333
# }

proc iflash_set_pemode { v } {
    mmw $::flash_addr(EFM_FWMC) $v 0x1
}

proc iflash_set_pemod { v } {
    mmw $::flash_addr(EFM_FWMC) [expr $v<<4] [expr 0x7<<4]
}

proc xflash-is-unlock { } {
    set ctrl [mrw $::flash_addr(EFM_FAPRT)]
    return [expr $ctrl&1]
}

proc xflash-busy { } {
    set ctrl [mrw $::flash_addr(EFM_FSR)]
    return [expr ($ctrl&0x100)==0]
}

# 需要解锁
proc xflash-unlock {} {
    echo "flash unlock!"

    # 解锁寄存器访问保护
    mww $::flash_addr(EFM_FAPRT) $::flash_addr(UNLOCK_FAPRT_KEY1);
    mww $::flash_addr(EFM_FAPRT) $::flash_addr(UNLOCK_FAPRT_KEY2);

    # mww $::flash_addr(EFM_KEY1) $::flash_addr(UNLOCK_KEY1);
    # mww $::flash_addr(EFM_KEY1) $::flash_addr(UNLOCK_KEY2);

    # 设定连续变成模式 PEMOD[2:0] = 0b011
    iflash_set_pemode 0x1
    iflash_set_pemod  0x3

    return [xflash-is-unlock]
}

proc xflash-busy-wait { } {
    set x 0
    while [xflash-busy] {
        after 200;
        incr x
        if $x>10 {
            return 1
        }
    }
    return 0
}

proc xflash-erase-page {addr} {
    # 需要检查是否正在执行闪存操作
    if [xflash-busy-wait] {
        echo "wait timeout!"
        return 0
    }
    #设置擦除模式
    iflash_set_pemode 1
    iflash_set_pemod 0x4
    # mww $::flash_addr(EFM_F0NWPRT) [expr 1<<($addr>>13)]
    mww $addr 0x12345678

    #等待BUSY==0
    xflash-busy-wait
    #清除OPTEND标识
    mww $::flash_addr(EFM_FSCLR) $::flash_addr(OPTEND)
    return 1
}

# 擦除指令
proc xflash-erase {addr {end -1}} {
    while 1 {
        xflash-erase-page $addr
        incr addr $::flash_addr(PAGE_SIZE)
        if $addr>$end {
            break
        }
    }
}

proc xflash-program-start {} {
    #解除所有写保护, 每一个位为8KByte, 一共256KBytes
    #  0x00000000~0x00001FFF    OTP的8Kbyte
    #  0x03000C00~0x03000FFF    OTP的1Kbyte
    # mmw $::flash_addr(EFM_FWMC) 0x3 0x7
    iflash_set_pemode 1
    iflash_set_pemod  3
    # mww $::flash_addr(EFM_F0NWPRT) 0xffffffff
}

#xflash-program-wait 有问题,不建议使用
proc xflash-program-wait { } {
    set x 0
    # [expr ([mrw 0x2004]&0x10)==0]
    while [expr ([mrw $::flash_addr(EFM_FSR)]&0x10)==0] {
        after 1;
        incr x
        if $x>10 {
            return 1
        }
    }

    mww $::flash_addr(EFM_FSCLR) 0x10
    set x 0
    while [expr ([mrw $::flash_addr(EFM_FSR)]&0x10)!=0] {
        after 1;
        incr x
        if $x>10 {
            return 1
        }
    }

    return 0
}

proc xflash-program {addr dat} {
    mww $addr $dat
    #xflash-program-wait;
    mww $::flash_addr(EFM_FSCLR) 0x12
}

proc xflash-program-end {} {
    # 关闭编程模式
    iflash_set_pemod 0
    iflash_set_pemode 0
    after 500;
    #mww $::flash_addr(EFM_F0NWPRT) 0x0
}

proc xflash-erase-all {} {
    # 现在测试256KB的flash

    #擦除命令
    #mmw $::flash_addr(EFM_FWMC) 0x5 0x7
    iflash_set_pemod 1
    iflash_set_pemod 0x5
    # mww $::flash_addr(EFM_F0NWPRT) 0xffffffff
    catch {mww 0x3f000 0x12345678}
    echo "erase all"
    set ret [xflash-busy-wait]
    mww $::flash_addr(EFM_FSCLR) $::flash_addr(OPTEND)
    #mmw $::flash_addr(EFM_FWMC) 0x0 0x7
    iflash_set_pemod 0x0
    return $ret
}

proc xflash-dump-all {} {
    # set addr $::flash_addr(FLASH_ADDR)
    # set max_addr $::flash_addr(FLASH_END)
    # #打开临时的导出文件
    # set f [open "dump.txt" "w+"]

    # while $addr<$max_addr {
    #     set v [mrw $addr]
    #     set hex [format "mww 0x%08X 0x%08X" $addr $v]
    #     puts $f $hex
    #     incr addr 0x4
    #     if $addr>=$max_addr {
    #         echo "dump end!";
    #         break;
    #     }
    # }

    # #关闭文件
    # close $f
}

# -----------------------------------
# 指令说明.每种指令都需要前置指令 (如下)
# xflash-unlock
# -----------------------------------
# 擦除目标扇区
# xflash-erase-page addr

# 擦除范围扇区
# xflash-erase addr end_addr

# 全擦除
# xflash-erase-all
# -----------------------------------
# 编程流程,     先解锁,擦除芯片.然后开始编程，接着mww 地址,数据.  最后结束编程.加锁
#    详细在  write_flash.tcl 文件
# xflash-unlock
# xflash-erase-all
# xflash-program-start
# source build/main_elf.tcl
# xflash-program-end
# xflash-lock

# -----------------------------------
